package pers.chao.cacheable.core;

import cn.hutool.core.collection.CollUtil;
import pers.chao.cacheable.core.annotation.CacheSet;
import pers.chao.cacheable.infrastructure.utils.ElementUtil;
import pers.chao.cacheable.infrastructure.utils.RedisOp;
import pers.chao.tool.spring.SpringElUtil;
import pers.chao.tool.validate.ObjValidator;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * Description: set缓存操作
 * <p>
 * 执行顺序：
 * 1.删除key(或清除指定元素) -> 结束
 * 2.需要整体替换时清除key内的所有元素 -> 缓存元素 -> 结束
 *
 * @author W.Chao
 * @date 2020/10/2 14:33
 **/
public class CacheSetProcessor extends AbstractCacheProcessor {
	private CacheSet annotation;

	public CacheSetProcessor(CacheSet annotation) {
		this.annotation = annotation;
	}


	@Override
	protected void preInfo() {
		logger.info("[Cache set previous INFO], @cache -> {}, @cacheSet -> {}", cacheConditionInfo(), annotation);
	}

	@Override
	public void parseRedisStructKeyOrOther() {

	}

	@Override
	public Object preQuery() {
		if (RedisOp.hasKey(finalKey)) {
			return RedisOp.sGet(finalKey);
		}
		return null;
	}

	@Override
	public void afterMethodOperate(Object o) {
		String evictElement = annotation.evictElement();
		boolean isReplaceAll = annotation.replaceAll();
		// 将元素封装到列表中
		List<Object> elements = ElementUtil.elementTransfer(o);

		if (evict) {
			RedisOp.del(finalKey);
			return;
		} else if (ObjValidator.isNotEmptyString(evictElement)) {
			ArrayList removedElements = SpringElUtil.parseSpringEL(method, new ArrayList<>(params.values()).toArray(), evictElement, ArrayList.class, CollUtil.newArrayList(evictElement));
			// 删除多个元素
			List finalRemoved = ElementUtil.transferElementType(removedElements, annotation.eqValueType());
			RedisOp.sRemove(finalKey, finalRemoved);
			return;
		}

		// 整体替换时先将所有元素清除
		if (isReplaceAll) {
			Set<Object> allElement = RedisOp.sGet(finalKey);
			RedisOp.sRemove(finalKey, allElement);
		}

		boolean isFirst = !RedisOp.hasKey(finalKey);
		// 缓存返回的元素
		// 过期期限
		if (isFirst && isNeedExpire) {
			RedisOp.sSet(finalKey, elements, expire, unit);
		} else {
			RedisOp.sSet(finalKey, elements);
		}
	}
}
